package main

import (
	"bytes"
	"context"
	"encoding/csv"
	"io"
	"log"
	"net/url"
	"os"
	"os/signal"
	"strconv"
	"strings"

	"gitee.com/wpkg/crawl"
	"github.com/PuerkitoBio/goquery"
)

//goland:noinspection HttpUrlsUsage
const baseURL = `http://wssq.sbj.cnipa.gov.cn:9080/tmsve/agentInfo_getAgentDljg.xhtml`

func main() {
	ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
	defer cancel()

	df, err := os.Create("备案代理机构名单(不含律所).csv")
	if err != nil {
		log.Fatalln(err)
	}
	defer closes(df)
	dw := csv.NewWriter(df)

	paramFunc := param(0, 0)
	c := crawl.New().RequestOpt(crawl.Referer(baseURL)).CookieEnabled()
	err = c.Crawl().PostForm(baseURL, paramFunc(1)).Process(process(c, dw, paramFunc)).Enqueue().Start(ctx)
	if err != nil {
		log.Println(err)
	}
	log.Println("完成")
}

type PageParamFunc = func(pageNum int) url.Values

func param(tabValue, pageSize int) PageParamFunc {
	if pageSize < 1 {
		pageSize = 1000
	}

	if tabValue < 0 {
		tabValue = 0
	}

	return func(pageNum int) url.Values {
		if pageNum < 1 {
			pageNum = 1
		}
		data := url.Values{}
		data.Set("tabValue", strconv.Itoa(tabValue))
		data.Set("pagesize", strconv.Itoa(pageSize))
		data.Set("gopage", strconv.Itoa(pageNum))
		data.Set("pagenum", strconv.Itoa(pageNum))
		return data
	}
}

func process(c *crawl.Crawler, dw *csv.Writer, paramFunc PageParamFunc, trimHeader ...bool) crawl.Processor {
	return crawl.ProcessBytes(func(data []byte) error {
		doc, err := goquery.NewDocumentFromReader(bytes.NewReader(data))
		if err != nil {
			return err
		}

		trs := doc.Find("table.import_tab").Find("table.import_tab").Find("tr")
		trs.Each(func(i int, tr *goquery.Selection) {
			var tds = tr.Find("td")
			var records []string

			tds.Each(func(_ int, td *goquery.Selection) {
				records = append(records, strings.TrimSpace(td.Text()))
			})

			if len(trimHeader) > 0 && trimHeader[0] && len(records) > 0 && records[0] == "序号" {
				return
			}

			var name string
			var phone string
			if len(records) > 1 {
				name = records[1]
			}
			if len(records) > 2 {
				phone = records[2]
			}

			if err := dw.Write(records); err != nil {
				log.Printf("%d: %s: %v\n", i, name, err)
			} else {
				log.Printf("%d: %s: %v\n", i, name, phone)
			}
		})

		dw.Flush()

		countPage, _ := doc.Find("#countpage").Attr("value")
		pageNum, _ := doc.Find("#pagenum").Attr("value")
		totalPage, _ := strconv.Atoi(countPage)
		curPage, _ := strconv.Atoi(pageNum)

		log.Printf("countPage: %s/%s\n", pageNum, countPage)
		log.Printf("countPage: %d/%d\n", curPage, totalPage)

		if totalPage > curPage {
			curPage++
			log.Printf("取第%d页\n", curPage)
			c.Crawl().PostForm(baseURL, paramFunc(curPage)).Process(process(c, dw, paramFunc, true)).Enqueue()
		}
		return nil
	})
}

func closes(closer io.Closer) {
	if closer != nil {
		if err := closer.Close(); err != nil {
			log.Println(err)
		}
	}
}
